<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Server Logs</title>
    <style>
        body {
            font-family: monospace;
            background: #1e1e1e;
            color: #d4d4d4;
            margin: 0;
            padding: 0;
        }
        #log-container {
            padding: 10px;
            height: 100vh;
            overflow-y: auto;
            white-space: pre-wrap;
        }
    </style>
</head>
<body>
    <div id="log-container"></div>

<script>
    /**
     * LogStreamer - Backwards-compatible log streaming client
     * Supports both WebSocket (Python server) and SSE (C++ server)
     * Tries WebSocket first, falls back to SSE if unavailable
     */
    class LogStreamer {
        constructor(baseUrl, onMessage, onError = null) {
            this.baseUrl = baseUrl;
            this.onMessage = onMessage;
            this.onError = onError;
            this.connection = null;
            this.type = null; // 'websocket' or 'sse'
        }
        
        async connect() {
            // Try WebSocket first (Python server)
            try {
                await this.connectWebSocket();
                console.log('[LogStreamer] Connected via WebSocket');
                return;
            } catch (wsError) {
                console.log('[LogStreamer] WebSocket failed, trying SSE...', wsError);
            }
            
            // Fallback to SSE (C++ server)
            try {
                this.connectSSE();
                console.log('[LogStreamer] Connected via SSE');
            } catch (sseError) {
                console.error('[LogStreamer] Both WebSocket and SSE failed', sseError);
                if (this.onError) {
                    this.onError(new Error('Unable to connect to log stream'));
                }
            }
        }
        
        connectWebSocket() {
            return new Promise((resolve, reject) => {
                const wsUrl = this.baseUrl
                    .replace('http://', 'ws://')
                    .replace('https://', 'wss://') + '/api/v1/logs/ws';
                
                const ws = new WebSocket(wsUrl);
                let connectionTimeout = setTimeout(() => {
                    reject(new Error('WebSocket connection timeout'));
                    ws.close();
                }, 3000); // 3 second timeout
                
                ws.onopen = () => {
                    clearTimeout(connectionTimeout);
                    this.connection = ws;
                    this.type = 'websocket';
                    resolve();
                };
                
                ws.onmessage = (event) => {
                    this.onMessage(event.data);
                };
                
                ws.onerror = (error) => {
                    clearTimeout(connectionTimeout);
                    if (this.onError && this.connection) {
                        this.onError(error);
                    }
                    reject(error);
                };
                
                ws.onclose = () => {
                    if (this.type === 'websocket') {
                        console.log('[LogStreamer] WebSocket closed');
                        if (this.onError) {
                            this.onError(new Error('WebSocket connection closed'));
                        }
                    }
                };
            });
        }
        
        connectSSE() {
            const sseUrl = this.baseUrl + '/api/v1/logs/stream';
            const eventSource = new EventSource(sseUrl);
            
            eventSource.onopen = () => {
                this.connection = eventSource;
                this.type = 'sse';
            };
            
            eventSource.onmessage = (event) => {
                this.onMessage(event.data);
            };
            
            eventSource.onerror = (error) => {
                console.error('[LogStreamer] SSE error:', error);
                if (this.onError) {
                    this.onError(error);
                }
            };
        }
        
        disconnect() {
            if (!this.connection) return;
            
            if (this.type === 'websocket') {
                this.connection.close();
            } else if (this.type === 'sse') {
                this.connection.close();
            }
            
            this.connection = null;
            this.type = null;
        }
        
        getConnectionType() {
            return this.type;
        }
    }

    // Utility functions
    function stripAnsi(str) {
        return str.replace(/\x1B\[[0-9;]*[A-Za-z]/g, '');
    }

    function isNearBottom() {
        const threshold = 50; // px from bottom
        return logContainer.scrollTop + logContainer.clientHeight >= logContainer.scrollHeight - threshold;
    }

    // Initialize log streaming
    const logContainer = document.getElementById("log-container");
    const baseUrl = `${location.protocol}//${location.host}`;
    
    const logStreamer = new LogStreamer(
        baseUrl,
        (logLine) => {
            // Handle incoming log line
            const line = document.createElement("div");
            line.textContent = stripAnsi(logLine);
            logContainer.appendChild(line);

            // Only autoscroll if the user is already at (or near) the bottom
            if (isNearBottom()) {
                logContainer.scrollTop = logContainer.scrollHeight;
            }
        },
        (error) => {
            // Handle error
            const msg = document.createElement("div");
            msg.textContent = `[Connection error: ${error.message}]`;
            msg.style.color = "red";
            logContainer.appendChild(msg);
        }
    );
    
    // Connect to log stream
    logStreamer.connect();
    
    // Show connection type in console
    setTimeout(() => {
        const type = logStreamer.getConnectionType();
        if (type) {
            console.log(`[LogViewer] Connected via ${type === 'websocket' ? 'WebSocket' : 'Server-Sent Events'}`);
        }
    }, 100);
</script>
</body>
</html>
